package com.inexas.cu.stratus;

import java.util.*;
import javax.jdo.*;

/**
 * This class implements the Stratus interface over Google's Bigtable
 */
public class BigtableStratus implements Stratus {

	public void create(Entity entity) {
		assert entity != null : "Null entity";
		
		final PersistenceManager pm = PMF.getInstance();
		try {
			pm.makePersistent(entity);
		} finally {
			pm.close();
		}
	}

	@SuppressWarnings("unchecked")
    public <T> T findByIdent(Class<T> entityType, Long ident) {
		assert entityType != null : "Entity type is null";
		assert ident != null : "Null ident";
		assert Entity.class.isAssignableFrom(entityType) :	//
			"Class must implement com.inexas.cu.stratus.Entity: " + entityType.getName();
		
		final T result;
		final PersistenceManager pm = PMF.getInstance();
		try {
			final Class<? extends Entity> btEntityType = (Class<? extends Entity>)entityType;
			result = (T)pm.getObjectById(btEntityType, ident);
			if(result == null) {
				throw new NoSuchEntityException(btEntityType, ident);
			}
		} finally {
			pm.close();
		}
		return result;
	}

	@SuppressWarnings("unchecked")
    public <T> Iterator<T> findAll(Class<T> entityType) {
		assert entityType != null : "Entity type is null";
		assert Entity.class.isAssignableFrom(entityType) :	//
			"Class must implement com.inexas.cu.stratus.Entity: " + entityType.getName();

		
		final PersistenceManager pm = PMF.getInstance();
		final Extent extent = pm.getExtent(entityType, false);
		try {
			return extent.iterator();
		} finally {
			extent.closeAll();
			pm.close();
		}
	}
	
	@SuppressWarnings("unchecked")
    public <T> T findBy(Class<T> entityType, String... constraints) {
		assert entityType != null : "Entity type is null";
		assert Entity.class.isAssignableFrom(entityType) :	//
			"Class must implement com.inexas.cu.stratus.Entity: " + entityType.getName();

		final PersistenceManager pm = PMF.getInstance();
		final Class<? extends Entity> btEntityType = (Class<? extends Entity>)entityType;
		final Query query = (new Constraints(constraints)).getQuery(pm, btEntityType);
		try {
			final List<Entity> results = (List<Entity>)query.execute();
			return (T)(results.size() == 0 ? null : results.get(0));
		} finally {
			query.closeAll();
			pm.close();
		}
	}
	
	@SuppressWarnings("unchecked")
    public <T> List<T> findAllBy(Class<T> entityType, String... constraints) {
		assert entityType != null : "Entity type is null";
		assert Entity.class.isAssignableFrom(entityType) :	//
			"Class must implement com.inexas.cu.stratus.Entity: " + entityType.getName();

		final PersistenceManager pm = PMF.getInstance();
		final Class<? extends Entity> btEntityType = (Class<? extends Entity>)entityType;
		final Query query = (new Constraints(constraints)).getQuery(pm, btEntityType);
		try {
			final List<T> result = (List<T>)query.execute();
			return result;
		} finally {
			query.closeAll();
			pm.close();
		}
	}

	public void update(Entity entity) throws NoSuchEntityException {
		assert entity != null : "Entity is null";
		assert entity.getIdent() != null && entity.getIdent().longValue() != 0 :	//
			"Entity ident is null or 0. Are you trying to update this entity when " +	//
			"you should be trying to make it persistent by calling create(entity)?";
		
		final PersistenceManager pm = PMF.getInstance();
		try {
			pm.makePersistent(entity);
		} finally {
			pm.close();
		}
	}

	public void delete(Entity entity) throws NoSuchEntityException {
		assert entity != null : "Entity is null";
		assert entity.getIdent() != null && entity.getIdent().longValue() != 0 :	//
			"Entity ident is null or 0";
		
		final PersistenceManager pm = PMF.getInstance();
		try {
			final Entity toDelete = pm.getObjectById(entity.getClass(), entity.getIdent());
			if(toDelete == null) {
				throw new NoSuchEntityException(toDelete);
			}
			pm.deletePersistent(toDelete);
		} finally {
			pm.close();
		}
	}

	public void deleteAll(Class<? extends Entity> entityType) {
		final Iterator<? extends Entity> i = findAll(entityType);
		while(i.hasNext()) {
			delete(i.next());
		}
	}
	
}
